/****************************************************************************
**
**	File Name   : Utilty.cpp
**
**	Project     : DatChecker
**
**	Last Updated: $Header: /DatChecker.root/DatChecker/Utility.cpp 1     8/14/03 9:25a Neusel $
**
**	Description : 
**
**		Utility functions for the DatChecker application.
**
****************************************************************************/
#include "stdafx.h"
/*	----------------------------------------------------------------------
	Global Declarations
	----------------------------------------------------------------------	*/

/*	----------------------------------------------------------------------
	Local Declarations
	----------------------------------------------------------------------	*/
static const int		kTmpStrCount	= 8;
static const int		kStrTmpLen	= 63;

static int				s_nBuffer = 0;
static TCHAR			s_cBuffer[kTmpStrCount][kStrTmpLen+1];
/*	----------------------------------------------------------------------
	Local Function Prototypes
	----------------------------------------------------------------------	*/

/****************************************************************************
**
**	PlaceWindow() -- places a window on the screen at the requested position
**		after verifying that the position is visible within the desktop.
**
*/
void
PlaceWindow(
	CWindow &		wnd,		// window to place
	RECT const &	rWhere)		// rectangle requested
{
RECT	rDummy, 
		rWorkArea;

if (!::IsRectEmpty(&rWhere) &&
	::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rWorkArea, NULL) &&
	::IntersectRect(&rDummy, &rWorkArea, &rWhere))
	{
	(void) wnd.SetWindowPos(NULL, &rWhere, 
							SWP_NOREDRAW | SWP_NOZORDER | SWP_NOACTIVATE);
	}
else
	wnd.CenterWindow();
}	/* end of PlaceWindow() */
/****************************************************************************
**
**	StrByteCount() --	formats a byte count into a MB/KB string
**
*/
LPTSTR						// ptr to output string (buffer)
StrByteCount(
	LONG	lBytes)			// # of bytes
{
double		fValue;
LPTSTR		pszResult = s_cBuffer[s_nBuffer];

s_nBuffer = (s_nBuffer + 1) % kTmpStrCount;

if (lBytes > GB(1))
	{
	fValue = double(lBytes) / GB(1);
	(void)_snprintf(pszResult, kStrTmpLen,
					_T("%.1fGB (%s bytes)"), 
					fValue, StrNum(lBytes));
	}
else if (lBytes > MB(1))
	{
	fValue = double(lBytes) / MB(1);
	(void)_snprintf(pszResult, kStrTmpLen,
					_T("%.1fMB (%s bytes)"), 
					fValue, StrNum(lBytes));
	}
else if (lBytes > KB(1))
	{
	fValue = double(lBytes) / KB(1);
	(void)_snprintf(pszResult, kStrTmpLen,
					_T("%.1fKB (%s bytes)"), 
					fValue, StrNum(lBytes));
	}
else
	{
	(void)_snprintf(pszResult, kStrTmpLen,
					_T("%s bytes"), 
					StrNum(lBytes));
	}

return pszResult;
}	/* end of StrByteCount() */
/****************************************************************************
**
**	StrCmpPartial() --	
**
*/
int								// CSTR_EQUAL, CSTR_LESS_THAN, CSTR_GREATER_THAN
StrCmpPartial(
	LPCTSTR		pstr1,			// left string
	LPCTSTR		pstr2,			// right string
	const bool	bCase)			// true for case-sensitive, false otherwise
{
if (NULL_PTR(pstr1))
	return GOOD_PTR(pstr2) ? CSTR_LESS_THAN : CSTR_EQUAL;

if (NULL_PTR(pstr2))
	return GOOD_PTR(pstr1) ? CSTR_GREATER_THAN : CSTR_EQUAL;
/*
**	Now actually compare the strings
*/
int		nCmp,
		nCmpLen;
SIZE_T	sLen1 = strlen(pstr1),
		sLen2 = strlen(pstr2);
DWORD	dwFlags = NORM_IGNORESYMBOLS | NORM_IGNOREWIDTH;

if (!bCase)
	dwFlags |= NORM_IGNORECASE;
	
nCmpLen = (int) min(sLen1, sLen2);
nCmp = ::CompareString(LOCALE_USER_DEFAULT, dwFlags, 
						pstr1, nCmpLen, pstr2, nCmpLen);

if (nCmp == 0)
	PANIC( ::GetLastError() );

return nCmp;
}	/* end of StrCmpPartial() */
/****************************************************************************
**
**	StrFileTime() -- formats a FILETIME structure as a string.
**
*/
LPTSTR
StrFileTime(
	FILETIME const &	ft)
{
SYSTEMTIME		st,
				stUTC;
LPTSTR			pszResult;
TCHAR			szDate[kStrTmpLen+1],
				szTime[kStrTmpLen+1];

::ZeroMemory(szDate, sizeof(szDate));
::ZeroMemory(szTime, sizeof(szTime));

pszResult = s_cBuffer[s_nBuffer];
s_nBuffer = (s_nBuffer + 1) % kTmpStrCount;

if (FileTimeToSystemTime(&ft, &stUTC) &&
	SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &st) &&
	GetDateFormat(NULL, DATE_LONGDATE, &st, NULL, szDate, kStrTmpLen) &&
	GetTimeFormat(NULL, TIME_NOSECONDS, &st, NULL, szTime, kStrTmpLen))
	{
	(void)_snprintf(pszResult, kStrTmpLen,
					_T("%s %s"),
					szTime, szDate);
	}
else
	strncpy(pszResult, _T("n/a"), kStrTmpLen);
	
return pszResult;
}	/* end of StrFileTime() */
/****************************************************************************
**
**	StrNum() --	formats a binary long to a string with commas (replaces
**					ltoa() and printf()/sprintf() functions)
**
*/
LPTSTR							// ptr to output string (buffer)
StrNum(
	long	lValue)				// value to convert
{
LPTSTR	pszResult;
TCHAR	szBuffer[kStrTmpLen+1];

pszResult = s_cBuffer[s_nBuffer];
s_nBuffer = (s_nBuffer + 1) % kTmpStrCount;

(void) _ltoa(lValue, szBuffer, 10);
//
//	Use Win32 API call to format the number
//
NUMBERFMT	nf;

::ZeroMemory(&nf, sizeof(NUMBERFMT));
nf.NumDigits		= 0;
nf.Grouping			= 3;
nf.lpDecimalSep		= ".";	//lint !e1776
nf.lpThousandSep	= ",";	//lint !e1776
nf.NegativeOrder	= 1;	// Negative sign, number. Example: -1.1
nf.LeadingZero		= 1;

if (!::GetNumberFormat(NULL, NULL, szBuffer, &nf, pszResult, kStrTmpLen))
	::ZeroMemory(pszResult, kStrTmpLen);

return pszResult;
}	/* end of StrNum() */
/****************************************************************************
**
**	$History: Utility.cpp $
 * 
 * *****************  Version 1  *****************
 * User: Neusel       Date: 8/14/03    Time: 9:25a
 * Created in $/DatChecker.root/DatChecker
**
**	-------------------------------------------------------------------------
**
**	End of Utility.cpp
**
****************************************************************************/
